/*
 * SipDialog.cpp
 *
 *  Created on: Dec 6, 2011
 *      Author: shaohong
 */

#include "SipDialog.h"
#include "SipHeader.h"
#include "AppLogger.h"
#include "SipServer.h"
#include "ParsingUtils.h"

#include <cstdio>

using namespace std;

namespace nmps {

static AppLogger * logger = AppLogger::getInstance("SipDialog");

SipDialog::SipDialog(string callID) {
	this->callID = callID;
	state = NEW;

	peerChannelNumber = 1;	//default channel number selected for a newly created dialog
	peerMediaIp = "";	// this the IP indicated by the peer's SDP
	peerMediaPort = 0;  // this is the port indicated by the peer's SDP
}

SipDialog::~SipDialog() {
	// TODO Auto-generated destructor stub
}

void SipDialog::handleBYE(SipRequest * sipRequest) {
	SipResponse *response = sipRequest->createResponse(200, "OK");
	logger->debug("send 200 for BYE");
	getSipServer()->sendSipMessage(response);

	//remove peer from the corresponding radioStreamer
	getSipServer()->removeRadioStreaming(peerChannelNumber, peerMediaIp, peerMediaPort);

	getSipServer()->removeDialog(callID);

}

void SipDialog::handleINFO(SipRequest * sipRequest) {
	logger->debug("handleINFO");
	SipResponse *response = sipRequest->createResponse(200, "OK");
	logger->debug("send 200 for INFO");
	getSipServer()->sendSipMessage(response);

	string contentStr = sipRequest->getContent();
	int dtmfDigit = ParsingUtils::extractDTMFSignal(contentStr);
	logger->error("DTMF digit is %d in INFO msg", dtmfDigit);

	if (getSipServer()->isValidChannelNumber(dtmfDigit)) {
		// remove the user from current current radioStreamer and attach him to a different channel
		getSipServer()->removeRadioStreaming(peerChannelNumber, peerMediaIp,
				peerMediaPort);

		peerChannelNumber = dtmfDigit;
		getSipServer()->addRadioStreaming(peerChannelNumber, peerMediaIp,
				peerMediaPort);
	} else {
		logger->error("invalid Channel Number \"%d\" in INFO msg", dtmfDigit);
	}

}

void SipDialog::handleInvite(SipRequest *sipRequest) {
	//this is a INVITE request
	if (state == NEW) {
		logger->debug("DialogState is NEW and received INVITE");
		// need to initialize the sipDialog a little bit with this request
		this->localUriAndParams = sipRequest->getHeader(SipHeader::TO_HNAME);
		this->peerUriAndParams = sipRequest->getHeader(SipHeader::FROM_HNAME);
		if (!SipMessage::hasTag(localUriAndParams)) {
			SipMessage::addTag(localUriAndParams);
		}
		sipRequest->setSipDialog(this);
		SipResponse *response = sipRequest->createResponse(180, "Rining");

		//send out the 180 response
		getSipServer()->sendSipMessage(response);
		state = EARLY;

		response = sipRequest->createResponse(200, "OK");
		string offerSDP = sipRequest->getContent();
		string answerSDP = SipMessage::createAnswerSDP(offerSDP);
		response->setContent("application/sdp", answerSDP);

		logger->debug("offerSDP=\n%s",offerSDP.c_str());
		peerMediaIp = SipMessage::extractRtpIP(offerSDP);
		peerMediaPort = SipMessage::extractRtpPort(offerSDP);
		logger->debug("clientIP=%s, clientPort=%d", peerMediaIp.c_str(), peerMediaPort);
		getSipServer()->addRadioStreaming(peerChannelNumber, peerMediaIp, peerMediaPort);

		logger->debug("send 200");
		getSipServer()->sendSipMessage(response);
		state = ESTABLISHED;

	}

}

void SipDialog::handleRequest(SipRequest *sipRequest) {
	const string INVITE_str = string("INVITE");
	const string ACK_str = string("ACK");
	const string BYE_str = string("BYE");
	const string INFO_str = string("INFO");
	logger->debug("handling request with callID %s\n",
			sipRequest->getCallID().c_str());
	string requestMethod = sipRequest->getMethod();
	//	fprintf(stderr, "requestMethod =\"%s\"", requestMethod.c_str());
	if (0 == requestMethod.compare(INVITE_str)) {
		//this is a INVITE request
		handleInvite(sipRequest);
		return;
	}

	if (0 == requestMethod.compare(BYE_str)) {
		//this is a INVITE request
		handleBYE(sipRequest);
		return;
	}

	if (0 == requestMethod.compare(INFO_str)) {
		//this is a INVITE request
		handleINFO(sipRequest);
		return;
	}


}

void SipDialog::handleResponse(SipResponse *sipResponse) {

}

void SipDialog::setSipServer(SipServer * sipServer) {
	this->sipServer = sipServer;
}

SipServer * SipDialog::getSipServer() {
	return this->sipServer;
}

} /* namespace nmps */
